The development of the EDVAC computer system of 1948 is often cited as the beginning of the computer era. Since that time, computer systems have evolved into extremely sophisticated devices, and computer systems may be found in many different settings. Computer systems typically include a combination of hardware, such as semiconductors and circuit boards, and software, also known as computer programs. As advances in semiconductor processing and computer architecture push the performance of the computer hardware higher, more sophisticated and complex computer software has evolved to take advantage of the higher performance of the hardware, resulting in computer systems today that are much more powerful than just a few years ago.
As the sophistication and complexity of computer software increase, the more difficult the software is to debug. Bugs are problems, faults, or errors in a computer program. Locating, analyzing, and correcting suspected faults in a computer program is a process known as “debugging.” Typically, a programmer uses another computer program commonly known as a “debugger” to debug a program under development.
Conventional debuggers typically support two primary operations to assist a computer programmer. A first operation supported by conventional debuggers is a “step” function, which permits a computer programmer to process instructions (also known as “statements”) in a computer program one-by-one and see the results upon completion of each instruction. While the step operation provides a programmer with a large amount of information about a program during its execution, stepping through hundreds or thousands of program instructions can be extremely tedious and time consuming, and may require a programmer to step through many program instructions that are known to be error-free before a set of instructions to be analyzed are executed.
To address this difficulty, a second operation supported by conventional debuggers is a breakpoint operation, which permits a computer programmer to identify with a breakpoint a precise instruction for which it is desired to halt execution of a computer program during execution. As a result, when a computer program is executed by a debugger, the program executes in a normal fashion until a breakpoint is reached. The debugger then stops execution of the program and displays the results of the program to the programmer for analysis.
Typically, step operations and breakpoints are used together to simplify the debugging process. Specifically, a common debugging operation is to set a breakpoint at the beginning of a desired set of instructions to be analyzed and then begin executing the program. Once the breakpoint is reached, the debugger halts the program, and the programmer then steps through the desired set of instructions line-by-line using the step operation. Consequently, a programmer is able to more quickly isolate and analyze a particular set of instructions without needing to step through irrelevant portions of a computer program.
Thus, once the programmer determines the appropriate places in the program and sets breakpoints at those appropriate places, the breakpoints can be a powerful tool. But, many breakpoints may be needed, and the breakpoints needed may change over time as the programmer gains more information about the problem being debugged. Hence, determining the appropriate places in the program, setting breakpoints at those places, and removing the breakpoints that are no longer needed can be an arduous task.
To make setting and removing breakpoints easier, some conventional debuggers have breakpoint groups. The primary use of these groups is to form a collection of breakpoints, which can be enabled and disabled all at once. Breakpoint groups allow the programmer to more rapidly adjust the debug environment and not be burdened by excessive and undesired breakpoint hits. While breakpoint groups can be a real time saver once they are set up, in situations as dynamic as debugging, programmers often experience difficulty in managing the group of breakpoints.
The difficulty in managing breakpoints is exacerbated when the program being debugged executes in multiple jobs. A job is a single process or task that is performed by the computer. Each job consists of allocated memory known as working storage and one or more execution states known as threads, which follow the control flow of program code saved in working storage. Jobs have unique designators associated with them for the purpose of identifying a particular job. A user who desires to perform a specific computer operation designates the execution path corresponding to the operation, and the computer accordingly creates the associated job. A computer processor in turn executes the created job, and the user's desired operation is initiated. A computer processor cycles through a sequence of jobs, generally servicing in some capacity each job. Multiple job environments can significantly complicate the debugging process, particularly when certain jobs are not amendable to debugging directly.
Some conventional debuggers support conditional breakpoints, which allow the user to set a breakpoint that fires only if a program variable achieves a certain value. For example, consider a standard “for loop” that increments the variable “i” once during each loop iteration. Conditional breakpoints allow the user to set a breakpoint that fires when the current value of “i” is greater than or equal to 10. While conditional breakpoints can be useful, they are limited to the current state of program variables.
Without a better way to manage breakpoints, conditional breakpoints, breakpoints in the threads of jobs, and breakpoint groups, the debugging of programs will continue to be a difficult and time-consuming task, which delays the introduction of software products and increases their costs.